package jsen.tool.ddd.adapter.infrastructure.strict;

import com.google.common.reflect.TypeToken;
import io.jsen.meta.diff.context.MetaContext;
import io.jsen.meta.diff.obj.MetaObject;
import io.jsen.meta.diff.support.MetaDiffModel;
import jsen.tool.ddd.adapter.infrastructure.specification.base.SpecContext;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;

/**
 * @author jsen
 * @date 2021/10/11
 */
public class StrictSpecContext<T> extends SpecContext<T> {
    private final T baseData;

    public StrictSpecContext(Map<String, String> specError, T data, Set<String> needSpecItem, T baseData) {
        super(specError, data, needSpecItem);
        this.baseData = baseData;
    }

    @Override
    public <S> SpecContext<S> subContext(Function<T, S> change) {
        S subData = change.apply(getData());
        S subBaseData = change.apply(baseData);
        return StrictSpecContext.create(getSpecError(), subData, subBaseData);
    }

    public static <T> SpecContext<T> create(T data, T baseData) {
        return create(new HashMap<>(4), data, baseData);
    }

    @SuppressWarnings({"UnstableApiUsage", "unchecked"})
    private static <T> SpecContext<T> create(Map<String, String> specError, T data, T baseData) {
        MetaDiffModel<T> model = new MetaDiffModel<>(TypeToken.of((Class<T>) data.getClass()), data, baseData);
        MetaObject<?, ?> metaObject = MetaContext.toMeta(model);
        Set<String> diffFieldSet = DiffHelp.getChangeFields(metaObject);

        return new StrictSpecContext<>(specError, data, diffFieldSet, baseData);
    }

}
